contents

1. 예외 처리란?


2. 자바 예외 모델

A. 예외 계층 구조

B. 예외 처리 흐름


3. 핵심 키워드


4. 예시

try {
    int[] arr = new int;
    int i = arr; // ArrayIndexOutOfBoundsException 발생
} catch (ArrayIndexOutOfBoundsException ex) {
    System.out.println("예외 처리됨: " + ex);
} finally {
    System.out.println("항상 실행됨.");
}

체크 예외 예시

public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path); // IOException 처리 또는 선언 필수
}

언체크 예외 예시

String x = null;
System.out.println(x.length()); // NullPointerException 발생(언체크)

5. 사용자 정의 예외 클래스

직접 예외 클래스를 정의할 수 있습니다:

public class InvalidOrderException extends RuntimeException {
    public InvalidOrderException(String message) {
        super(message);
    }
}

6. 스프링 부트에서의 예외 처리


7. 베스트 프랙티스


8. 요약 비교표

개념 체크 예외 언체크(런타임) 예외
처리 필수 여부 아니오
메서드 선언 필요 throws로 선언 선택적으로 선언 가능
주요 예시 IOException, SQLException NullPointerException, IndexOutOfBoundsException

요약:
자바와 스프링의 예외 처리는 오류를 감지·복구·전달하여 유지보수성과 안정성, 사용자 친화성을 높여줍니다. 핵심 로직 분리, 적절한 예외 클래스를 통한 관리, 모니터링 및 적절한 오류 응답으로 견고한 소프트웨어 개발에 필수적입니다.


Spring Boot에서 자주 사용되는 에러 처리 방식을 보겠습니다.


1. 기본 에러 응답(Spring Boot)

Spring Boot에서 에러가 별도로 처리되지 않을 경우, 기본적으로 아래와 같이 JSON 형태의 에러 응답이 반환됩니다:

{
  "timestamp": "2019-09-16T22:14:45.624+0000",
  "status": 404,
  "error": "Not Found",
  "message": "Book with id 1 not found",
  "path": "/api/book/1"
}

이 구조는 이벤트 시각, HTTP 상태 코드, 에러 명칭, 메시지, 요청 경로를 포함합니다.


2. 커스텀 글로벌 예외 처리

전체 컨트롤러에서 응답 구조를 일관성 있게 커스터마이즈하려면 @RestControllerAdvice 또는 @ControllerAdvice@ExceptionHandler를 활용합니다.

커스텀 에러 객체 예시:

public class ApiError {
    private String type;
    private String title;
    private int status;
    private String detail;
    private String instance;
    // 생성자, getter, setter 등
}

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ApiError> handleNotFound(ResourceNotFoundException ex, HttpServletRequest request) {
        ApiError error = new ApiError(
            "/errors/resource-not-found",
            "Resource Not Found",
            404,
            ex.getMessage(),
            request.getRequestURI()
        );
        return ResponseEntity.status(404).body(error);
    }
}

이 방식으로 일관된 구조의 에러 응답을 만듭니다.


3. RFC 7807 및 ProblemDetail 활용

Spring Boot 3+ 최신 API는 RFC 7807("HTTP API의 표준 에러 응답") 형식도 적극 사용합니다.

예시 구조:

{
  "type": "/errors/incorrect-user-pass",
  "title": "Incorrect username or password.",
  "status": 401,
  "detail": "Authentication failed due to incorrect username or password.",
  "instance": "/login/log/abc123"
}

4. ProblemDetail 활용(Spring Boot 3+)

import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.*;

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ResourceNotFoundException.class)
    public ProblemDetail handleNotFound(ResourceNotFoundException ex, HttpServletRequest request) {
        ProblemDetail detail = ProblemDetail.forStatus(HttpStatus.NOT_FOUND);
        detail.setTitle("Resource Not Found");
        detail.setDetail(ex.getMessage());
        detail.setInstance(URI.create(request.getRequestURI()));
        detail.setType(URI.create("/errors/not-found"));
        return detail;
    }
}

표준화된 머신 읽기/쓰기 가능한 에러 응답을 제공합니다.


5. 베스트 프랙티스


요약:
Spring 기반 웹 애플리케이션은 @ControllerAdvice 등 중앙화 예외 처리로 모든 에러를 예측 가능한 구조의 JSON 응답으로 변환하며, 커스텀 에러 객체 혹은 ProblemDetail 같은 표준 객체를 이용해 디버깅과 API 사용성을 향상시킵니다.

references